package com.loong.data.handler;

import com.alibaba.fastjson.JSON;
import com.loong.common.exception.GlobalException;
import com.loong.common.rabbitmq.dto.GoodsSpecificationDTO;
import com.loong.common.utils.TransformUtils;
import com.loong.data.common.backend.param.GoodsSpecificationParam;
import com.loong.data.common.backend.param.PageParam;
import com.loong.data.common.backend.result.GoodsSpecificationForeheadResult;
import com.loong.data.common.backend.result.GoodsSpecificationResult;
import com.loong.data.common.forehead.param.*;
import com.loong.data.dto.GoodsSpecificationDTOResult;
import com.loong.data.model.GoodsSpecificationModel;
import com.loong.data.repository.GoodsSpecificationRepository;
import com.loong.data.utils.ESPageUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.UpdateByQueryRequest;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description:
 * @Author: hzp
 * @Date: 2020-12-5 9:45
 */
@Component
@Slf4j
public class GoodsSpecificationHandler {
    @Resource
    private GoodsSpecificationRepository goodsSpecificationRepository;

    @Resource
    private RestHighLevelClient client;

    @Resource
    private ElasticsearchRestTemplate template;

    /**
     * 新增商品规格到es：MQ消费者中调用该方法
     *
     * @param goodsSpecificationDTO 商品类型参数
     */
    public void saveGoodsSpecificationModel(GoodsSpecificationDTO goodsSpecificationDTO) {
        goodsSpecificationRepository.save(TransformUtils.transform(goodsSpecificationDTO, GoodsSpecificationModel.class));
    }

    /**
     * 更新商品类型信息到es：MQ消费者中调用该方法
     *
     * @param goodsSpecificationDTO 商品类型参数
     */
    public void updateGoodsSpecificationModel(GoodsSpecificationDTO goodsSpecificationDTO) {
        if(ObjectUtils.isEmpty(goodsSpecificationDTO.getGoodsSpecificationNewName())){
            //创建更新请求
            UpdateRequest request = new UpdateRequest("goods_specification", goodsSpecificationDTO.getId().toString());
            //将要更新的数据以json格式封装到请求中
            request.doc(JSON.toJSONString(goodsSpecificationDTO), XContentType.JSON);
            //执行更新请求的操作
            try {
                client.update(request, RequestOptions.DEFAULT);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }else {

            UpdateByQueryRequest request = new UpdateByQueryRequest("goods_specification");
            // 更新时版本冲突
            request.setConflicts("proceed");
            // 设置查询条件，第一个参数是字段名，第二个参数是字段的值
            request.setQuery(new TermQueryBuilder("goodsSpecificationId",goodsSpecificationDTO.getGoodsSpecificationId() ));
            // 批次大小
            request.setBatchSize(1000);
            request.setScript(new Script(ScriptType.INLINE, "painless",
                    updateParamBuild(goodsSpecificationDTO), Collections.emptyMap()));
            // 刷新索引
            request.setRefresh(true);
            log.debug("buildStr====="+updateParamBuild(goodsSpecificationDTO));
            try {
                BulkByScrollResponse bulkByScrollResponse = client.updateByQuery(request, RequestOptions.DEFAULT);
            } catch (IOException e) {
                new GlobalException("更新规格名称出现异常",e);
            }


        }

    }
    private String updateParamBuild(GoodsSpecificationDTO goodsSpecificationDTO){
        StringBuilder sb = new StringBuilder();
        sb.append("if (ctx._source.goodsSpecificationId == "+goodsSpecificationDTO.getGoodsSpecificationId()+") " +
                "{"
                +"ctx._source.goodsSpecificationName = '"+goodsSpecificationDTO.getGoodsSpecificationNewName()+"';");
                sb.append("}");
        return sb.toString();


    }

    /**
     * 根据id删除es中的商品规格：MQ消费者中调用该方法
     *
     * @param ids 商品类型信息id
     */
    public void deleteGoodsSpecificationModelByIds(String ids) {
        if(ObjectUtils.isEmpty(ids))return;
        String[] idArrays = ids.split(",");
        Arrays.stream(idArrays).forEach(id -> goodsSpecificationRepository.deleteById(Long.parseLong(id)));
    }


    /**
     * 公共方法：分页查询商品规格
     * @param param 查询和分页封装的参数
     * @return 商品规格集合
     */
    public List<GoodsSpecificationDTO> commonPageQueryGoodsSpecification(GoodsSpecificationAndPageForeheadParam param) {
        PageForeheadParam pageParam = null;
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        if (ObjectUtils.isNotEmpty(param)&&ObjectUtils.isNotEmpty(param.getGoodsSpecificationForeheadParam())){

            //构建查询条件
            if (ObjectUtils.isNotEmpty(param.getGoodsSpecificationForeheadParam().getGoodsSpecificationName())) {
                //商品类型名称进行精确查询
                boolQuery.must(QueryBuilders.matchPhraseQuery("goodsSpecificationName", param.getGoodsSpecificationForeheadParam().getGoodsSpecificationName()));
            }
            if (ObjectUtils.isNotEmpty(param.getGoodsSpecificationForeheadParam().getShopId())){
                boolQuery.must(QueryBuilders.termQuery("shopId",param.getGoodsSpecificationForeheadParam().getShopId()));
            }
            if (ObjectUtils.isNotEmpty(param.getGoodsSpecificationForeheadParam().getGoodsSpecificationId())){
                boolQuery.must(QueryBuilders.termQuery("goodsSpecificationId",param.getGoodsSpecificationForeheadParam().getGoodsSpecificationId()));
            }
            if(!CollectionUtils.isEmpty(param.getGoodsSpecificationForeheadParam().getIdList())){
                List<Long> idList = param.getGoodsSpecificationForeheadParam().getIdList();
                idList.forEach(id->{
                    boolQuery.should(QueryBuilders.termQuery("id",id));
                });
            }
        }else{
            boolQuery.must(QueryBuilders.matchAllQuery());
        }
        //分页参数
        if (ObjectUtils.isNotEmpty(param.getPageParam())){
            pageParam = param.getPageParam();
        }
        Pageable pageable = ESPageUtil.getPageableByParam(pageParam);
        return executeQuery(boolQuery,pageable);
    }

    /**
     * 后台多条件分页查询店铺规格
     *
     * @param goodsSpecificationParam 店铺规格查询参数
     * @param pageParam 分页参数
     * @return 店铺规格集合
     */
    public List<GoodsSpecificationResult> pageQueryGoodsSpecificationModel(GoodsSpecificationParam  goodsSpecificationParam, PageParam pageParam) {
        //后台多条件查询参数转换成前台多条件查询参数
        GoodsSpecificationForeheadParam goodsSpecificationForeheadParam = null;
        PageForeheadParam pageForeheadParam = null;
        if (ObjectUtils.isNotEmpty(goodsSpecificationParam)) {
            goodsSpecificationForeheadParam = TransformUtils.transform(goodsSpecificationParam, GoodsSpecificationForeheadParam.class);
        }
        if (ObjectUtils.isNotEmpty(pageParam)) {
            pageForeheadParam = TransformUtils.transform(pageParam, PageForeheadParam.class);
        }
        GoodsSpecificationAndPageForeheadParam param = GoodsSpecificationAndPageForeheadParam.builder()
                .goodsSpecificationForeheadParam(goodsSpecificationForeheadParam)
                .pageParam(pageForeheadParam)
                .build();
        //获取查询结果
        List<GoodsSpecificationDTO> goodsSpecificationDTOS = this.commonPageQueryGoodsSpecification(param);
        if (CollectionUtils.isEmpty(goodsSpecificationDTOS)) return null;
        return TransformUtils.transformList(goodsSpecificationDTOS, GoodsSpecificationResult.class);
    }


    /**
     * 执行查询请求，并获得结果
     * @param queryBuilder 查询条件
     * @return 商品规格集合
     */
    private List<GoodsSpecificationDTO> executeQuery(QueryBuilder queryBuilder, Pageable pageable){
        //存放商品规格信息的集合
        List<GoodsSpecificationModel> modelList = new ArrayList<>();
        //构建查询条件
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(queryBuilder)
                .withPageable(pageable)
                .build();
        //获得查询的结果
        SearchHits<GoodsSpecificationModel> hits = template.search(searchQuery, GoodsSpecificationModel.class);
        List<SearchHit<GoodsSpecificationModel>> hitList = hits.getSearchHits();
        for (SearchHit<GoodsSpecificationModel> hit : hitList) {
            GoodsSpecificationModel model = hit.getContent();
            modelList.add(model);
        }
        return TransformUtils.transformList(modelList,GoodsSpecificationDTO.class);
    }

    public List<GoodsSpecificationForeheadResult> findGoodsSpecificationForeheadResult(GoodsSpecificationAndPageForeheadParam param) {
        param.setPageParam(PageForeheadParam.builder().pageIndex(0).pageSize(10000).build());
        List<GoodsSpecificationDTO> goodsSpecificationDTOS = this.commonPageQueryGoodsSpecification(param);
        List<GoodsSpecificationResult> goodsSpecificationResults = TransformUtils.transformList(goodsSpecificationDTOS, GoodsSpecificationResult.class);
        List<GoodsSpecificationForeheadResult> resultList = new ArrayList<>();
        Map<Long, List<GoodsSpecificationResult>> maps = goodsSpecificationResults.stream().collect(Collectors.groupingBy(GoodsSpecificationResult::getGoodsSpecificationId, Collectors.toList()));
        maps.forEach((k,v)->{
            resultList.add(GoodsSpecificationForeheadResult.builder().goodsSpecificationId(k).result(v).build());
        });
        return resultList;
    }


    public GoodsSpecificationDTOResult findGoodsSpecificationById(Long id){
        if(goodsSpecificationRepository.findById(id).isPresent()){
            return TransformUtils.transform(goodsSpecificationRepository.findById(id).get(),GoodsSpecificationDTOResult.class);
        }
        return null;
    }
}
